﻿#include "parseutil.h"

#define STARTPOSITION_SESSIONID 4
#define STARTPOSITION_STREAM 6
#define STARTPOSITION_FUNCTION 7
#define STARTPOSITION_PTYPE 8
#define STARTPOSITION_STYPE 9
#define STARTPOSITION_TRANSACTIONID 10
#define STARTPOSITION_TEXT0 14
#define STARTPOSITION_TEXT1 15
#define WITH_REPLY_MASK 0x80

quint16 ParseUtil::Get_SessionId(QByteArray array)
{
    return ConversionUtil::ByteArrayToU2(array.mid(STARTPOSITION_SESSIONID, 2));
}

quint32 ParseUtil::Get_TransactionId(QByteArray array)
{
    return ConversionUtil::ByteArrayToU4(array.mid(STARTPOSITION_TRANSACTIONID, 4));
}

quint8 ParseUtil::Get_Stream(QByteArray array)
{
    if(Is_PrimaryMessage(array))
    {
        return ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STREAM, 1)) ^ WITH_REPLY_MASK;
    }

    if(Is_ReplyMessage(array))
    {
        return ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STREAM, 1));
    }
}

quint8 ParseUtil::Get_Function(QByteArray array)
{
    return ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_FUNCTION, 1));
}

SecsEnum::Formate ParseUtil::Get_DataType(QByteArray array)
{
    if(Is_DataMessage(array))
    {
        quint8 formate = array.at(STARTPOSITION_TEXT0) & 11111100;
        switch(formate)
        {
        case 0x00 : return SecsEnum::LIST; break;
        case 0x24 : return SecsEnum::BOOLEAN; break;
        case 0x40 : return SecsEnum::ASCII; break;
        case 0xa4 : return SecsEnum::U1; break;
        case 0xa8 : return SecsEnum::U2; break;
        case 0xb0 : return SecsEnum::U4; break;
        case 0xa0 : return SecsEnum::U8; break;
        case 0x64 : return SecsEnum::I1; break;
        case 0x68 : return SecsEnum::I2; break;
        case 0x70 : return SecsEnum::I4; break;
        case 0x60 : return SecsEnum::I8; break;
        case 0x90 : return SecsEnum::F4; break;
        case 0x80 : return SecsEnum::F8; break;
        case 0x20 : return SecsEnum::BINARY; break;
        default : return SecsEnum::None; break;
        }
    }
}

SecsEnum::SelectStatus ParseUtil::Get_SelectStatus(QByteArray array)
{
    if(Is_SelectRsp(array))
    {
        quint8 select_status = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_FUNCTION, 1));
        switch(select_status)
        {
        case 0 : return SecsEnum::CommunicationEstablished; break;

        case 1 : return SecsEnum::CommunicationAlreadyActive; break;

        case 2 : return SecsEnum::ConnectionNotReady; break;

        case 3 : return SecsEnum::ConnectExhaust; break;

        default : return SecsEnum::OtherSelectStatus; break;
        }
    }
}

SecsEnum::DeselectStatus ParseUtil::Get_DeselectStatus(QByteArray array)
{
    if(Is_DeselectRsp(array))
    {
        quint8 deselect_status = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_FUNCTION, 1));
        switch(deselect_status)
        {
        case 0 : return SecsEnum::CommunicationEnded; break;

        case 1 : return SecsEnum::CommunicationNotEstablished; break;

        case 2 : return SecsEnum::CommunicationBusy; break;

        default : return SecsEnum::OtherDeselectStatus; break;
        }
    }
}

SecsEnum::RejectReasonCode ParseUtil::Get_RejectReasonCode(QByteArray array)
{
    if(Is_RejectReq(array))
    {
        quint8 reject_reason_code = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_FUNCTION, 1));
        switch(reject_reason_code)
        {
        case 1 : return SecsEnum::STypeNotSupport; break;

        case 2 : return SecsEnum::PTypeNotSupport; break;

        case 3 : return SecsEnum::TransactionNotOpen; break;

        case 4 : return SecsEnum::EntityNotSelected; break;

        default : return SecsEnum::OtherRejectReasonCode; break;
        }
    }
}

bool ParseUtil::Is_DataMessage(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::DATA)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_ControlMessage(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype != SecsEnum::DATA)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_PrimaryMessage(QByteArray array)
{
    quint8 function = Get_Function(array);

    if(function % 2 == 0)
    {
        return false;
    }

    return true;
}

bool ParseUtil::Is_ReplyMessage(QByteArray array)
{
    quint8 function = Get_Function(array);

    if(function % 2 == 0)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_SelectReq(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::SELECT_REQ)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_SelectRsp(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::SELECT_RSP)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_DeselectReq(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::DESELECT_REQ)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_DeselectRsp(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::DESELECT_RSP)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_LinkTestReq(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::LINKTEST_REQ)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_LinkTestRsp(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::LINKTEST_RSP)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_RejectReq(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::REJECT)
    {
        return true;
    }

    return false;
}

bool ParseUtil::Is_SeparateReq(QByteArray array)
{
    quint8 stype = ConversionUtil::ByteArrayToU1(array.mid(STARTPOSITION_STYPE, 1));

    if(stype == SecsEnum::SEPARATE)
    {
        return true;
    }

    return false;
}

Text *ParseUtil::Get_MessageText(QByteArray array)
{
    if(array.length() == 14)
    {
        return nullptr;
    }
    return Get_MessageText(array, STARTPOSITION_TEXT0);
}

Text *ParseUtil::Get_MessageText(QByteArray array, int startPosition)
{
    char info = array.at(startPosition);

    int info_formate = info & 0xfc;
    int info_length = info & 0x03;

    int totlaLength = array.at(startPosition + 1);

    if (info_length > 1)
    {
        totlaLength |= (array.at(startPosition + 2) << 8);
    }

    if (info_length > 2)
    {
        totlaLength |= (array.at(startPosition + 3) << 16);
    }

    if (info_length > 3)
    {
        totlaLength |= (array.at(startPosition + 4) << 24);
    }

    startPosition += (info_length + 1);

    Text* data {nullptr};
    switch(info_formate)
    {
    case SecsEnum::LIST :
        data = parseLIST(array, startPosition, totlaLength);
        break;

    case SecsEnum::ASCII :
        data = parseASCII(array, startPosition, totlaLength);
        break;

    case SecsEnum::BOOLEAN :
        data = parseBool(array, startPosition, totlaLength);
        break;

    case SecsEnum::F4 :
        data = parseF4(array, startPosition, totlaLength);
        break;

    case SecsEnum::F8 :
        data = parseF8(array, startPosition, totlaLength);
        break;

    case SecsEnum::I1 :
        data = parseI1(array, startPosition, totlaLength);
        break;

    case SecsEnum::I2 :
        data = parseI2(array, startPosition, totlaLength);
        break;

    case SecsEnum::I4 :
        data = parseI4(array, startPosition, totlaLength);
        break;

    case SecsEnum::I8 :
        data = parseI8(array, startPosition, totlaLength);
        break;

    case SecsEnum::U1 :
        data = parseU1(array, startPosition, totlaLength);
        break;

    case SecsEnum::U2 :
        data = parseU2(array, startPosition, totlaLength);
        break;

    case SecsEnum::U4 :
        data = parseU4(array, startPosition, totlaLength);
        break;

    case SecsEnum::U8 :
        data = parseU8(array, startPosition, totlaLength);
        break;

    case SecsEnum::BINARY :
        data = parseBinary(array, startPosition, totlaLength);
        break;
    }

    return data;
}

TextList *ParseUtil::parseLIST(QByteArray msg, int startPosition, int length)
{
    TextList* list = new TextList();

    for (int i = 0; i < length; ++i)
    {
        Text* item = Get_MessageText(msg, startPosition);
        list->addItem(item);
        startPosition += item->getByteArray().length();
    }

    return list;
}

TextASCII *ParseUtil::parseASCII(QByteArray msg, int startPosition, int length)
{
    QString data;

    for (int i = startPosition; i < startPosition + length; ++i)
    {
        data.append(msg.at(i));
    }

    return new TextASCII(data);
}

TextBoolean *ParseUtil::parseBool(QByteArray msg, int startPosition, int length)
{
    if(msg.at(startPosition))
    {
        return new TextBoolean(true);
    }

    return new TextBoolean(false);
}

TextF4 *ParseUtil::parseF4(QByteArray msg, int startPosition, int length)
{
    std::vector<float> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::F4_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToF4(msg.mid(i, SecsEnum::F4_LENGTH)));
    }

    return new TextF4(list);
}

TextF8 *ParseUtil::parseF8(QByteArray msg, int startPosition, int length)
{
    std::vector<double> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::F8_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToF8(msg.mid(i, SecsEnum::F8_LENGTH)));
    }

    return new TextF8(list);
}

TextI1 *ParseUtil::parseI1(QByteArray msg, int startPosition, int length)
{
    std::vector<qint8> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::I1_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToI1(msg.mid(i, SecsEnum::I1_LENGTH)));
    }

    return new TextI1(list);
}

TextI2 *ParseUtil::parseI2(QByteArray msg, int startPosition, int length)
{
    std::vector<qint16> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::I2_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToI2(msg.mid(i, SecsEnum::I2_LENGTH)));
    }

    return new TextI2(list);
}

TextI4 *ParseUtil::parseI4(QByteArray msg, int startPosition, int length)
{
    std::vector<qint32> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::I4_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToI4(msg.mid(i, SecsEnum::I4_LENGTH)));
    }

    return new TextI4(list);
}

TextI8 *ParseUtil::parseI8(QByteArray msg, int startPosition, int length)
{
    std::vector<qint64> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::I8_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToI8(msg.mid(i, SecsEnum::I8_LENGTH)));
    }

    return new TextI8(list);
}

TextU1 *ParseUtil::parseU1(QByteArray msg, int startPosition, int length)
{
    std::vector<quint8> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::U1_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToU1(msg.mid(i, SecsEnum::U1_LENGTH)));
    }

    return new TextU1(list);
}

TextU2 *ParseUtil::parseU2(QByteArray msg, int startPosition, int length)
{
    std::vector<quint16> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::U2_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToU2(msg.mid(i, SecsEnum::U2_LENGTH)));
    }

    return new TextU2(list);
}

TextU4 *ParseUtil::parseU4(QByteArray msg, int startPosition, int length)
{
    std::vector<quint32> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::U4_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToU4(msg.mid(i, SecsEnum::U4_LENGTH)));
    }

    return new TextU4(list);
}

TextU8 *ParseUtil::parseU8(QByteArray msg, int startPosition, int length)
{
    std::vector<quint64> list;

    for (int i = startPosition; i < startPosition + length; i += SecsEnum::U8_LENGTH)
    {
        list.push_back(ConversionUtil::ByteArrayToU8(msg.mid(i, SecsEnum::U8_LENGTH)));
    }

    return new TextU8(list);
}

TextBinary *ParseUtil::parseBinary(QByteArray msg, int startPosition, int length)
{
    std::vector<char> list;

    for (int i = 0; i < length; i += SecsEnum::B_LENGTH)
    {
        list.push_back(msg.at(startPosition + i));
    }

    return new TextBinary(list);
}

